package com.strato.mvc.security.v1_0_0.enhancer;

import java.lang.reflect.Method;
import java.util.Map;

import com.strato.annotation.osgi.v1_0_0.service.OsgiService;
import com.strato.annotation.osgi.v1_0_0.service.OsgiWired;
import com.strato.base.env.v1_0_0.GlobalEnvironment;
import com.strato.mvc.annotation.v1_0_0.invoker.MethodHttpInvoker;
import com.strato.mvc.api.v1_0_0.control.HttpInvoker;
import com.strato.mvc.api.v1_0_0.control.PathVariableCollector;
import com.strato.mvc.api.v1_0_0.control.RequestMappingRegistry;
import com.strato.mvc.api.v1_0_0.user.Principal;
import com.strato.mvc.api.v1_0_0.user.SaasPrincipal;
import com.strato.mvc.api.v1_0_0.user.UserContext;
import com.strato.mvc.api.v1_0_0.view.ModelEnhancer;
import com.strato.mvc.security.v1_0_0.annotation.SecurityConstraint;
import com.strato.mvc.security.v1_0_0.api.AuthorityService;
import com.strato.mvc.security.v1_0_0.api.UrlAuthChecker;
import com.strato.saas.merchant.v1_0_0.MerchantContextHolder;
import com.strato.transaction.v1_0_0.api.jdbc.DataSourceTransactionManager;
import com.strato.transaction.v1_0_0.api.jdbc.Execution;

@OsgiService(id="authorityEnhancer")
public class AuthorityEnhancer implements ModelEnhancer,UrlAuthChecker {

	private String MODEL_KEY="authUtil";
	
	@Override
	public void enhance(Map<Object, Object> model) {
		model.put(MODEL_KEY, this);
	}
	
	@OsgiWired
	private AuthorityService authorityService;
	
	public boolean has(String url){
		RequestMappingRegistry registry=RequestMappingRegistry.getInstance();
		PathVariableCollector pvc=new PathVariableCollector();
		HttpInvoker invoker = registry.getMappedInvoker(url,pvc);
		if(invoker==null){
			return true;
		}
		MethodHttpInvoker methodInvoker=(MethodHttpInvoker) invoker;
		Method method = methodInvoker.getMethod();
		SecurityConstraint sc = method.getAnnotation(SecurityConstraint.class);
		if(sc==null){
			return true;
		}
		String opers = sc.value();
		opers=GlobalEnvironment.getInstance().resolveString(opers);
		if(opers==null||opers.length()==0){
			return true;
		}
		Principal principal = UserContext.getPrincipal();
		if(principal==null){
			return false;
		}
		return checkOpers(principal,opers);
	}

	private boolean checkOpers(final Principal principal, final String opers) {
		String[] operations=opers.split(",|;");
		String backupMerchant=MerchantContextHolder.get();
		if(SaasPrincipal.class.isInstance(principal)){
			String merchantId=((SaasPrincipal)principal).getMerchantId();
			MerchantContextHolder.set(merchantId);
		}
		try{
			return DataSourceTransactionManager.requiresNew(new Execution<Boolean>() {
				@Override
				public Boolean execute() {
					return authorityService.check(principal,operations);
				}
			});
		}finally{
			MerchantContextHolder.set(backupMerchant);
		}
	}
	
}
